//
//  RegexCategoriesTests.swift
//  Tests
//
//  Created by LL on 2023/4/7.
//

import XCTest

final class RegexCategoriesTests: XCTestCase {
    func test_isMatch() throws {
        let regex = try RX("mof+")
        XCTAssertTrue(regex.isMatch("moff"))
        XCTAssertFalse(regex.isMatch("mov"))
    }
    
    
    func test_firstRange() throws {
        let regex = try RX("mof+")
        XCTAssertEqual(regex.firstRange("moff"), NSRange(location: 0, length: 4))
        XCTAssertNil(regex.firstRange("mov"))
    }
    
    
    func test_firstValue() throws {
        let regex = try RX("mof+")
        XCTAssertEqual(regex.firstValue("moff"), "moff")
        XCTAssertNil(regex.firstValue("mov"))
    }
    
    
    func test_values() throws {
        let regex = try RX("mof+")
        LILAssertEqualArray(regex.values("moff mof"), ["moff", "mof"])
        LILAssertEqualArray(regex.values("mov"), [])
    }
    
    
    func test_firstMatch() throws {
        let regex = try RX("mo(?<name>f+)")
        let match = regex.firstMatch("moff")
        XCTAssertEqual(match?.value, "moff")
        XCTAssertEqual(match?.range, NSRange(location: 0, length: 4))
        XCTAssertEqual(match?.value(1), "ff")
        XCTAssertEqual(match?.value("name"), "ff")
        XCTAssertEqual(match?.range(1), NSRange(location: 2, length: 2))
        XCTAssertEqual(match?.range("name"), NSRange(location: 2, length: 2))
        
        XCTAssertNil(regex.firstMatch("mov"))
    }
    
    
    func test_matches() throws {
        let regex = try RX("mo(?<name>f+)")
        let matches = regex.matches("moff mof")
        XCTAssertEqual(matches[0].value, "moff")
        XCTAssertEqual(matches[0].range, NSRange(location: 0, length: 4))
        XCTAssertEqual(matches[0].value(1), "ff")
        XCTAssertEqual(matches[0].value("name"), "ff")
        XCTAssertEqual(matches[0].range(1), NSRange(location: 2, length: 2))
        XCTAssertEqual(matches[0].range("name"), NSRange(location: 2, length: 2))
        
        XCTAssertEqual(matches[1].value, "mof")
        XCTAssertEqual(matches[1].range, NSRange(location: 5, length: 3))
        XCTAssertEqual(matches[1].value(1), "f")
        XCTAssertEqual(matches[1].value("name"), "f")
        XCTAssertEqual(matches[1].range(1), NSRange(location: 7, length: 1))
        XCTAssertEqual(matches[1].range("name"), NSRange(location: 7, length: 1))
        
        XCTAssertTrue(regex.matches("movv mov").isEmpty)
    }
    
    
    func test_enumerateMatches() throws {
        let regex = try RX("mo(?<name>f+)")
        var values: [NSString] = []
        var ranges: [NSRange] = []
        var subValues: [NSString?] = []
        var subRanges: [NSRange?] = []
        
        regex.enumerateMatches("moff mof") { (result: RxMatch) in
            values.append(result.value)
            ranges.append(result.range)
            subValues.append(result.value(1))
            subValues.append(result.value("name"))
            subRanges.append(result.range(1))
            subRanges.append(result.range("name"))
        }
        
        let values_answer: [NSString] = ["moff", "mof"]
        let ranges_answer: [NSRange] = [NSRange(location: 0, length: 4), NSRange(location: 5, length: 3)]
        let subValues_answer: [NSString?] = ["ff", "ff", "f", "f"]
        let subRanges_answer: [NSRange?] = [NSRange(location: 2, length: 2), NSRange(location: 2, length: 2), NSRange(location: 7, length: 1), NSRange(location: 7, length: 1)]
        
        LILAssertEqualArray(values, values_answer)
        LILAssertEqualArray(ranges, ranges_answer)
        LILAssertEqualArray(subValues, subValues_answer)
        LILAssertEqualArray(subRanges, subRanges_answer)
    }
    
    
    func test_replace() throws {
        let regex = try RX("ruf+")
        XCTAssertEqual(regex.replace("ruf ruff!", "move"), "move move!")
        XCTAssertEqual(regex.replace("ruv ruv!", "move"), "ruv ruv!")
    }
    
    
    func test_replace_hanlder_NSString() throws {
        let regex = try RX("ruf+")
        let content = regex.replace("ruf ruff!") { (value: NSString) in
            if value.hasPrefix("ruff") {
                return "move"
            } else {
                return "mov"
            }
        }
        XCTAssertEqual(content, "mov move!")
    }
    
    
    func test_replace_hanlder_RxMatch() throws {
        let regex = try RX("ru(f+)")
        let content = regex.replace("ruf ruff!") { (match: RxMatch) in
            if match.value(1) == "ff" {
                return "move"
            } else {
                return "mov"
            }
        }
        XCTAssertEqual(content, "mov move!")
    }
}



final class RegexStringTests: XCTestCase {
    func test_toRx() throws {
        XCTAssertNil("abc(?<=a*)def".toRx)
        XCTAssertNotNil("abc+".toRx)
    }
    
    
    func test_toRx_options() throws {
        XCTAssertNil("abc(?<=a*)def".toRx(.caseInsensitive))
        XCTAssertNotNil("abc+".toRx(.caseInsensitive))
    }
    
    
    func test_isMatch() throws {
        XCTAssertTrue("moff".isMatch(try RX("mof+")))
        XCTAssertFalse("mov".isMatch(try RX("mof+")))
    }
    
    
    func test_firstRange() throws {
        XCTAssertEqual("moff".firstRange(try RX("mof+")), NSRange(location: 0, length: 4))
        XCTAssertNil("mov".firstRange(try RX("mof+")))
    }
    
    
    func test_firstValue() throws {
        XCTAssertEqual("moff".firstValue(try RX("mof+")), "moff")
        XCTAssertNil("mov".firstValue(try RX("mof+")))
    }
    
    
    func test_values() throws {
        LILAssertEqualArray("moff mof".values(try RX("mof+")), ["moff", "mof"])
        LILAssertEqualArray("movv mov".values(try RX("mof+")), [])
    }
    
    
    func test_firstMatch() throws {
        let regex = try RX("mo(?<name>f+)")
        let match = "moff".firstMatch(regex)
        XCTAssertEqual(match?.value, "moff")
        XCTAssertEqual(match?.range, NSRange(location: 0, length: 4))
        XCTAssertEqual(match?.value(1), "ff")
        XCTAssertEqual(match?.value("name"), "ff")
        XCTAssertEqual(match?.range(1), NSRange(location: 2, length: 2))
        XCTAssertEqual(match?.range("name"), NSRange(location: 2, length: 2))
        
        XCTAssertNil("mov".firstMatch(regex))
    }
    
    
    func test_matches() throws {
        let regex = try RX("mo(?<name>f+)")
        let matches = "moff mof".matches(regex)
        
        XCTAssertEqual(matches[0].value, "moff")
        XCTAssertEqual(matches[0].range, NSRange(location: 0, length: 4))
        XCTAssertEqual(matches[0].value(1), "ff")
        XCTAssertEqual(matches[0].value("name"), "ff")
        XCTAssertEqual(matches[0].range(1), NSRange(location: 2, length: 2))
        XCTAssertEqual(matches[0].range("name"), NSRange(location: 2, length: 2))
        
        XCTAssertEqual(matches[1].value, "mof")
        XCTAssertEqual(matches[1].range, NSRange(location: 5, length: 3))
        XCTAssertEqual(matches[1].value(1), "f")
        XCTAssertEqual(matches[1].value("name"), "f")
        XCTAssertEqual(matches[1].range(1), NSRange(location: 7, length: 1))
        XCTAssertEqual(matches[1].range("name"), NSRange(location: 7, length: 1))
        
        XCTAssertTrue("movv mov".matches(regex).isEmpty)
    }
    
    
    func test_enumerateMatches() throws {
        let regex = try RX("mo(?<name>f+)")
        var values: [NSString] = []
        var ranges: [NSRange] = []
        var subValues: [NSString?] = []
        var subRanges: [NSRange?] = []
        
        "moff mof".enumerateMatches(regex) { (result: RxMatch) in
            values.append(result.value)
            ranges.append(result.range)
            subValues.append(result.value(1))
            subValues.append(result.value("name"))
            subRanges.append(result.range(1))
            subRanges.append(result.range("name"))
        }
        
        let values_answer: [NSString] = ["moff", "mof"]
        let ranges_answer: [NSRange] = [NSRange(location: 0, length: 4), NSRange(location: 5, length: 3)]
        let subValues_answer: [NSString?] = ["ff", "ff", "f", "f"]
        let subRanges_answer: [NSRange?] = [NSRange(location: 2, length: 2), NSRange(location: 2, length: 2), NSRange(location: 7, length: 1), NSRange(location: 7, length: 1)]
        
        LILAssertEqualArray(values, values_answer)
        LILAssertEqualArray(ranges, ranges_answer)
        LILAssertEqualArray(subValues, subValues_answer)
        LILAssertEqualArray(subRanges, subRanges_answer)
    }
    
    
    func test_replacingMatch() throws {
        let regex = try RX("ruf+")
        XCTAssertEqual("ruf ruff!".replacingMatch(regex, "move"), "move move!")
        XCTAssertEqual("ruv ruv!".replacingMatch(regex, "move"), "ruv ruv!")
    }
    
    
    func test_replacingMatch_hanlder_NSString() throws {
        let regex = try RX("ruf+")
        let content = "ruf ruff!".replacingMatch(regex) { (value: NSString) in
            if value.hasPrefix("ruff") {
                return "move"
            } else {
                return "mov"
            }
        }
        XCTAssertEqual(content, "mov move!")
    }
    
    
    func test_replacingMatch_hanlder_RxMatch() throws {
        let regex = try RX("ru(f+)")
        let content = "ruf ruff!".replacingMatch(regex) { (match: RxMatch) in
            if match.value(1) == "ff" {
                return "move"
            } else {
                return "mov"
            }
        }
        XCTAssertEqual(content, "mov move!")
    }
}



final class RegexMutableStringTests: XCTestCase {
    func test_replaceMatch() throws {
        let regex = try RX("ruf+")
        let mutableString = NSMutableString("ruf ruff!")
        mutableString.replaceMatch(regex, "move")
        XCTAssertEqual(mutableString, "move move!")
    }
    
    
    func test_replaceMatch_handler_NSString() throws {
        let regex = try RX("ruf+")
        let mutableString = NSMutableString("ruf ruff!")
        mutableString.replaceMatch(regex) { value in
            if value.hasPrefix("ruff") {
                return "move"
            } else {
                return "mov"
            }
        }
        XCTAssertEqual(mutableString, "mov move!")
    }
    
    
    func test_replaceMatch_handler_RxMatch() throws {
        let regex = try RX("ru(f+)")
        let mutableString = NSMutableString("ruf ruff!")
        mutableString.replaceMatch(regex) { match in
            if match.value(1) == "ff" {
                return "move"
            } else {
                return "mov"
            }
        }
        XCTAssertEqual(mutableString, "mov move!")
    }
}
